/*
 * mm.h
 * 
 * Manejador de Memoria
 *  
 */

#ifndef __MM_H__
#define __MM_H__

#include <types.h>

/** Atributos para Page Table Entry de 4 KB **/

#define MM_ATTR_PTE_P   	0x001 	// Present
#define MM_ATTR_PTE_NP		0x000	// Not Present
#define MM_ATTR_PTE_WRITE 	0x002 	// Write
#define MM_ATTR_PTE_READ  	0x000 	// Read
#define MM_ATTR_PTE_USER	0x004 	// Usuario
#define MM_ATTR_PTE_SUPERV	0x000 	// Supervisor
#define MM_ATTR_PTE_PWT		0x008	// Page Write-Through
#define MM_ATTR_PTE_PCD		0x010	// Page Cache Disable
#define MM_ATTR_PTE_A		0x020	// Accessed
#define MM_ATTR_PTE_NA		0x000	// Not Accessed
#define MM_ATTR_PTE_D		0x040	// Dirty
#define MM_ATTR_PTE_ND		0x000	// Not Dirty
#define MM_ATTR_PTE_PAT		0x080	// Page Table Attibute Index
#define MM_ATTR_PTE_NPAT	0x000	// Not Page Table Attibute Index
#define MM_ATTR_PTE_G		0x100	// Global
#define MM_ATTR_PTE_NG		0x000	// Not Global

#define MM_ATTR_PTE_PADDR(ptentry) ((void *) (ptentry & BITS_12_31))	// Direccion fisica de la pagina apuntada

/** Atributos para Page Directory Entry (que apunta a un PT) **/

#define MM_ATTR_PDE_P		0x001	// Present
#define MM_ATTR_PDE_NP		0x000	// Not Present
#define MM_ATTR_PDE_WRITE	0x002	// Write
#define MM_ATTR_PDE_READ	0x000	// Read
#define MM_ATTR_PDE_USER	0x004	// Usuario
#define MM_ATTR_PDE_SUPERV	0x000	// Supervisor
#define MM_ATTR_PDE_PWT		0x008	// Page Write-Through
#define MM_ATTR_PDE_PCD		0x010	// Page Cache Disable
#define MM_ATTR_PDE_A		0x020	// Accessed
#define MM_ATTR_PDE_NA		0x000	// Not Accessed
#define MM_ATTR_PDE_PS		0x000	// Debe ser 0

#define MM_ATTR_PDE_PADDR(pdentry) ((void *) (pdentry & BITS_12_31))	// Direccion fisica del Page Table apuntado

/** Mascaras para bits de Page Table Entry **/

#define MM_PTE_STATE_BITS		0xE00	// Toma los bits 9 10 y 11 (ignorados) utiliados para saber el estado de la pagina

/** Valores para los bits de estado anteriores **/

#define MM_PTE_ASSIGNED_PAGE	000000000000b
#define MM_PTE_SHARED_PAGE		001000000000b

/** Otros **/

#define MM_PD_ENTRIES		1024
#define MM_PT_ENTRIES		MM_PD_ENTRIES

#define MM_PD_INDEX(laddr)	(((uint32_t)(laddr) & BITS_22_31) >> 22)	// Indice en PD
#define MM_PT_INDEX(laddr)	(((uint32_t)(laddr) & BITS_12_21) >> 12)	// Indice en PT

#define MM_PAGE_SIZE		0x1000

#define MM_ALIGN_TO_PAGE_START(paddr) 	((void*) ((uint_32) paddr & 0xFFFFFF00))

/** Flags de Registros de Control **/

#define CR0_PE		0x00000001		// Protection Enable
#define CR0_MP		0x00000002		// Monitor coProcessor
#define CR0_EM		0x00000004		// Emulation
#define CR0_TS		0x00000008		// Task Switched
#define CR0_ET		0x00000010		// Extension Type
#define CR0_NE		0x00000020		// Numeric Errror
#define CR0_WP		0x00010000		// Write Protect
#define CR0_AM		0x00040000		// Alignment Mask
#define CR0_NW		0x20000000		// Not Writethrough
#define CR0_CD		0x40000000		// Cache Disable
#define CR0_PG		0x80000000		// Paging

#define CR4_PCE		0x00000100		// Performance Counter Enable
#define CR4_MCE		0x00000040		// Machine Check Enable
#define CR4_PSE		0x00000010		// Page Size Extensions
#define CR4_DE		0x00000008		// Debugging Extensions
#define CR4_TSD		0x00000004		// Time Stamp Disable
#define CR4_PVI		0x00000002		// Protected-Mode Virtual Interrupts
#define CR4_VME		0x00000001		// V86 Mode Extensions

/** Macro para crear entradas en Page Table o Page Directory **/

#define MM_MAKE_ENTRY(addr, attr) 	((mm_page_entry) {(uint_32)(attr), (uint_32)(addr) >> 12})
#define MM_NULL_ENTRY				((mm_page_entry) {0, 0})

/**
 * Entrada de Page Table o Page Directory. **/

typedef struct str_mm_page_entry
{
	uint_32 attr:12;
	uint_32 base:20;
} __attribute__((__packed__, aligned (4))) mm_page_entry;

/** 
 * Nodo para las listas de paginas libres.
 * 
 * Los mismos son ubicados al comienzo de cada pagina libre. **/

typedef struct str_mm_page_node mm_page_node;

struct str_mm_page_node
{
    int cant_ref;
    mm_page_node *next;
    mm_page_node *prev;
} __attribute__((__packed__));

/* Funciones */

void  mm_init();
void* mm_mem_alloc();
void* mm_mem_kalloc();
void  mm_mem_free(void *phaddr);

mm_page_entry* mm_dir_new();
void mm_dir_free(uint_32 *page_dir);

uint_32 mm_ram_amount();

void mm_debug_kernel_free_pages();
void mm_debug_user_free_pages();

/* Syscalls */

//void* palloc(void);

#endif /* __MM_H__ */
